<template>
  <div class="if-home">
    <div class="if-home-left">
      <div class="if-home-left-header">
        <el-popover
          placement="right-start"
          title="注意"
          :width="300"
          trigger="hover"
          content="用于生成html元素的ID，确保唯一，可以用交易码等"
        >
          <template #reference>
            <span>domID前缀</span>
          </template>
        </el-popover>           
        <el-input v-model="pageId" @change="handlePreview" />
        <!-- <div>
          容器选择
        </div> -->
        <el-radio-group v-show="false" v-model="layoutSelected" placeholder="容器选择">
          <el-radio-button
            v-for="(item, index) in layoutArr"
            :key="item.boxId"
            :label="item.boxId"
            border
          >
            {{ item.labelName }}
          </el-radio-button>
        </el-radio-group>        
      </div>
      <!-- accordion -->
      <el-collapse v-model="activeName">
        <el-collapse-item title="" name="rongqi">
          <template #title>
            <div class="collapse-title">容器</div>
          </template>
          <div v-for="item in containerArr" :key="item.componentName" class="component-name-box">
            <el-button @click="addLayout(item)">{{ item.componentNameShow }}<span class="jiahao">+</span></el-button>
          </div>
        </el-collapse-item>
        <el-collapse-item title="基础组件列表" name="jichuzujianliebiao"> <template #title>
            <div class="collapse-title">基础组件列表</div>
          </template>          
          <div v-for="item in baseComponentsList" :key="item.componentName" class="component-name-box">
            <el-button @click="addItem(item)">{{ item.componentNameShow }}<span class="jiahao">+</span></el-button>
          </div>
        </el-collapse-item>
        <el-collapse-item title="业务组件列表" name="yewuzujianliebiao">
          <template #title>
            <div class="collapse-title">业务组件列表</div>
          </template>          
          <div v-for="item in componentsList" :key="item.componentName" class="component-name-box">
            <el-button @click="addItem(item)">{{ item.componentNameShow }}<span class="jiahao">+</span></el-button>
          </div>
        </el-collapse-item>
      </el-collapse>      
    </div>
    <div class="if-home-center">
      <div class="if-home-center-btn">
        <!-- type="success" -->
        <el-button title="当前布局管理,可以对组件进行排序" @click="layoutManageHandle">当前布局管理</el-button>
        <el-button @click="handleExport('Html')">复制html</el-button>
        <el-button @click="handleExport('Js')">复制js</el-button>
        <el-button type="info" title="当前布局下载" @click="handleDownload()">下载<el-icon><download /></el-icon></el-button>        
        <el-button title="使用说明" @click="myHelpRef.drawer = true">帮助<el-icon><question-filled /></el-icon></el-button>        
        <!-- <el-button type="primary" title="当前布局新增" @click="addCurrentLayout()">新增<el-icon><document-add /></el-icon></el-button>         -->
      </div>
      <div id="vueIFApp"></div>
      <toolBtns @handleEdit="toolBtnsEdit" @handleDelete="toolBtnsDelete" ref="toolBtnsRef"/>   
    </div>
    <div class="if-home-right">
      <!-- 用来入库 -->
      <layoutManageSave ref="layoutManageSaveRef" :current-layout-obj="{layoutArr,pageId}" @on-edit="layoutManageSaveEdit" />     
    </div>     
    <el-dialog v-model="dialogVisible" @close="dialogVisible = false">
      <template #header>
        <div v-draggableDialog>修改</div>
      </template>
      <template #default>
        <ItemForm v-model="CurItemFormObj" />
      </template>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="saveFormItem">保存</el-button>
        </span>
      </template>      
    </el-dialog> 
    <!-- 用来排序 -->
    <layoutManage ref="layoutManageRef" v-model="layoutManageModel" @on-save="layoutManageHandleSave" @on-edit="layoutManageHandleEdit" />     
    <myHelp ref="myHelpRef" />  
  </div>
</template>
<script lang="ts" setup>
import { initApp } from '../../../main.js'
import { useRouter } from 'vue-router';
import { ref,reactive,defineOptions,toRaw,onMounted,watch,createApp,computed  } from 'vue';
import { ElMessage } from 'element-plus'
import {loadBaseCompnents,baseComponentsMap,baseComponentArr} from './baseComponents/index'
import {loadCompnents,componentsMap as componentsMap_,componentArr as componentArr_} from './components/index'
import {loadContainers,containerMap as containerMap_,containerArr as containerArr_} from './layouts/index'
import ItemForm from './ItemForm.vue'
import layoutManage from './layoutManage.vue'
import layoutManageSave from './layoutManageSave.vue'
import myHelp from './myHelp.vue'
import toolBtns from './toolBtns.vue'
import {getPage,copyToClipboard, generateFiles,getVueSetupJs} from './index.js'
import {componentValidMap,containerValidMap} from './config.js'
import {globalApp} from '../../main'
import validateFunction from '../common/validateFunction' // 交易页面也要引入此对象
import componentRules from '../common/componentRules' // 交易页面也要引入此对象
window.componentRules = componentRules
import mittBus from '@/utils/mittBus';
console.log('validateFunction',validateFunction);
defineOptions({ name: 'Home' });
// 加载公共组件，用于预览的app #vueIFApp使用
const commonComponentsObj = {}
const commonComponentRequired = import.meta.glob('@/example/youHH/commonComponent/*/index.vue')
for (const [path,definition] of Object.entries(commonComponentRequired)) {
    // 动态导入组件并注册为全局组件
    definition().then(component => {
        commonComponentsObj[component.default.name] = component.default || component
    })
}
const containerMap = reactive({}) // 所有布局类型
const containerArr = ref([]) // 所有布局类型
const baseComponentsList = ref([]) // 所有组件类型
const componentsList = ref([]) // 所有组件类型
// 所有已添加的组件和容器组件都在此对象中
const componentsMap = reactive({}) // 在handlePreview方法中生成，componentsMap和layoutsList的中的引用对象是同一个，componentsMap能方便找到引用对象进行修改
let layoutArr = reactive([]) // 添加到页面的布局列表
// const itspIframe = ref() // iframe dom对象
const layoutSelected = ref('') // 选中的布局
const htmlStrRef = ref('') // 生成的html字符串
const scriptStrRef = ref('') // 生成的script字符串
const pageId = ref(`c_${Date.now()}`) // 页面domID的前缀
let CurItemFormObj = reactive({}) // 当前修改的表单配置i对象
const dialogVisible = ref(false) // 修改弹窗可见性
const activeName = ref('zujianliebiao')
const layoutManageRef = ref()
const myHelpRef = ref()
const toolBtnsRef = ref()
const layoutManageSaveRef = ref()
const layoutManageModel = ref([])
window.dialogVisible = dialogVisible
window.componentsList = componentsList.value
window.layoutArr = layoutArr
window.componentsMap = componentsMap
window.CurItemFormObj = CurItemFormObj
window.layoutManageRef = layoutManageRef
// 载入所有基础组件
loadBaseCompnents.then(()=>{
  baseComponentsList.value = baseComponentArr
})
// 载入所有组件
loadCompnents.then(()=>{
  componentsList.value = componentArr_
})
// 载入所有布局
loadContainers.then(()=>{
  Object.assign(containerMap,containerMap_)
  containerArr.value = containerArr_
  mittBus.emit('loadContainers', { some: 'payload' });
})
// 添加表单组件
function addItem (item) {
  // 如果添加的是表格组件
  if (item.componentName === 'yc-web-table') {
    // 自动帮用户事先添加一个空容器
    addLayout(containerMap['ifContainer'],{preview:false})
  }
  let layoutItem = layoutArr.find(ele => ele.boxId === layoutSelected.value)
  // 校验组件和容器是否存在不适配情况 开始
  if (!layoutItem) {
      ElMessage({
        message: '请选中当前布局中的容器后添加',
        type: 'warning',
      })
      return    
  }
  let containerComponentName = layoutItem.componentName
  // 校验添加的组件是否可以添加到当前容器
  let containerArr = componentValidMap[item.componentName]
  let componentArr = containerValidMap[containerComponentName]
  // 存在要检验的容器信息就校验
  if (containerArr) {
    if (!containerArr.includes(containerComponentName)) {
      ElMessage({
        message: '当前组件和容器不适配，请换个容器',
        type: 'warning',
      })
      return
    }
  }
  if (componentArr) {
    if (!componentArr.includes(item.componentName)) {
      ElMessage({
        message: '当前组件和容器不适配，请换个容器',
        type: 'warning',
      })
      return
    }
  }
  // 校验组件和容器是否存在不适配情况 结束
  item = JSON.parse(JSON.stringify(toRaw(item)))
  // 信息框表单组件默认禁用
  if (containerComponentName === 'ifInfoBoxForm') {
    item.inputType = '禁用'
  }
  let {componentName} = item
  const newItem = reactive(item); // 可以复制全新的响应式对象
  newItem.layoutID = layoutSelected.value // 记录当前表单组件属于哪个布局id
  // 将表单组件添加到选中的布局中
  layoutItem.children.push(newItem)
  handlePreview()
  // 如果是立马需要做配置的组件，就打开它的编辑弹窗
  let arr = ['yc-btn-container','yc-web-table']
  if (arr.includes(componentName)) {
    // 
    // editFormItem(newItem)
  }
}
function addLayout (item,options = {preview:true}) {
  // console.log('%c item','font-size:24px;color:red;',item)
  item = JSON.parse(JSON.stringify(toRaw(item)))
  // children必须初始化成一个新数组，不然原始的item上的children的值将被共用
  const newItem = reactive(item); // 可以复制全新的响应式对象
  layoutArr.push(newItem)
  newItem.labelName += layoutArr.length
  handlePreview(options)
  layoutSelected.value = newItem.boxId
}
function editFormItem (item) {
  item = JSON.parse(JSON.stringify(toRaw(item)))
  dialogVisible.value = true
  // 编辑的时候需要复制一份item对象
  CurItemFormObj = item
}
// 保存组件配置
function saveFormItem () {
  dialogVisible.value = false
  let {boxId} = CurItemFormObj
  Object.assign(componentsMap.value[boxId],CurItemFormObj)
  handlePreview()
  // 更新布局管理的数据
  layoutManageModel.value = JSON.parse(JSON.stringify(toRaw(layoutArr)))
}
function toolBtnsEdit (boxId) {
    let editItem = componentsMap.value[boxId]
    editFormItem(editItem)  
}
function toolBtnsDelete (boxId) {
    let editItem = componentsMap.value[boxId]
    let {layoutID} = editItem
    // 如果有layoutID值，则说明不是容器组件
    if (layoutID) {
      // 找到所属容器
      let editLayoutItem = layoutArr.find(item => item.boxId === layoutID)
      // 找到要删除的索引
      let deleteIndex = editLayoutItem.children.findIndex(item => item.boxId === boxId)
      editLayoutItem.children.splice(deleteIndex,1)
    } else {
      // 找到要删除的容器索引
      let deleteIndex = layoutArr.findIndex(item => item.boxId === boxId)
      layoutArr.splice(deleteIndex,1)        
      if (layoutSelected.value === boxId && layoutArr[0]) {
        layoutSelected.value = layoutArr[0].boxId
      }
    }
    handlePreview()
}
onMounted(() => {
  mittBus.on('loadContainers', () => {
      if (layoutArr.length >= 2) {
        handlePreview()
        return 
      }
      // 默认添加一个邮储新容器
      addLayout(containerMap['ifNewLayout'])
      // 不能连续添加容器，生成的boxId，因为是生成的时间戳，可出现boxId相同的情况
      // addLayout(containerMap['ifContainer'])
      layoutSelected.value = layoutArr[0].boxId  
  });
  window.addEventListener('message', function(event) {
    // if (event.origin !== 'https://example.com') {
    //   return;
    // }
    let {type , param = {}} = event.data
    if (!type) {
      // 通信规则必须要有type才处理
      // console.log('%c type','font-size:24px;color:red;',type)
      return
    }
    let {boxId} = param
    if (type === '修改') {
      let editItem = componentsMap.value[boxId]
      editFormItem(editItem)
    }
    if (type === '删除') {
      let editItem = componentsMap.value[boxId]
      let {layoutID} = editItem
      // 如果有layoutID值，则说明不是容器组件
      if (layoutID) {
        // 找到所属容器
        let editLayoutItem = layoutArr.find(item => item.boxId === layoutID)
        // 找到要删除的索引
        let deleteIndex = editLayoutItem.children.findIndex(item => item.boxId === boxId)
        editLayoutItem.children.splice(deleteIndex,1)
      } else {
        // 找到要删除的容器索引
        let deleteIndex = layoutArr.findIndex(item => item.boxId === boxId)
        layoutArr.splice(deleteIndex,1)        
        if (layoutSelected.value === boxId && layoutArr[0]) {
          layoutSelected.value = layoutArr[0].boxId
        }
      }
      handlePreview()
    }
    if (type === 'onNavtabLoad') {
      if (layoutArr.length >= 2) {
        handlePreview()
        return 
      }
      // 默认添加一个邮储新容器
      addLayout(containerMap['ifNewLayout'])
      // 不能连续添加容器，生成的boxId，因为是生成的时间戳，可出现boxId相同的情况
      // addLayout(containerMap['ifContainer'])
      layoutSelected.value = layoutArr[0].boxId
      // let tableCom = componentsMap_['yc-web-table']
      // addItem(tableCom)
    }
    if (type === 'onContainerClick') {
      let {containerId} = param
      layoutSelected.value = containerId
    }
  });

})
function handlePreview (options = {preview:true}) {
  let {htmlStr,scriptStr} = getPage(layoutArr,pageId.value)
  // 生成一个map,key为容器id或者组件id,值为容器或区间
  componentsMap.value = {}
  layoutArr.forEach(item => {
    componentsMap.value[item.boxId] = item
    item.children.forEach(ele => {
      componentsMap.value[ele.boxId] = ele
    })

  })
  htmlStrRef.value = htmlStr
  scriptStrRef.value = scriptStr
  if (options.preview) {
    // itspIframe.value.contentWindow.postMessage({type:'pageInfo',htmlStr,scriptStr,containerId:layoutSelected.value}, '*');
    let vueIFApp = document.querySelector('#vueIFApp')
    // 测试demo，看自己生成的代码和标准代码哪里没对上
    // htmlStr = htmlStrGet()
    // scriptStr = scriptStrGet()
    // 定义一个Vue组件
    const getApp = () => {
      const App = {
        components: commonComponentsObj,        
        setup() {
          /* 
          */
         let totalData
          const defaultLayoutOptions = {
            xs: 12,
            sm: 8,
            md: 8,
            lg: 6,
            xl: 4
          };
        const currentLayoutOptions = computed(() => {
          return { ...defaultLayoutOptions };
        });
         eval(`
           ${scriptStr}
         `)
         totalData.currentLayoutOptions = currentLayoutOptions
         window.totalData = totalData
          return totalData;
        },
        template: `${htmlStr}`,
        beforeDestroy() {
          console.log('22222',22222);
        },
        mounted () {
          setTimeout(() => {
            // 实现组件工具栏
            let selector = [
              '#vueIFApp .el-card__header',
              '#vueIFApp .el-form-item__label',
              '#vueIFApp .form-button-group-div',
            ];
            // 表单label元素被替换成新label元素了，虽然id一样，导致事件没有监听,所以放在定时器里去监听事件
            [...document.querySelectorAll(selector.join(','))].forEach(item => {
              item.addEventListener('mouseenter',(e) => {
                let ele = e.target
                let eleRect = ele.getBoundingClientRect()
                let boxId = ele.parentNode.getAttribute('id') || ele.parentNode.parentNode.getAttribute('id') || ele.parentNode.parentNode.parentNode.getAttribute('id')
                toolBtnsRef.value.setPosition({x:eleRect.x+100,y:eleRect.y},boxId)
              })

            })

            // 容器点击
            let containerSelector = ['#vueIFApp .el-card'];
            [...document.querySelectorAll(containerSelector.join(','))].forEach(item => {
              item.addEventListener('click',(e) => {
                hignLigntContainer(item)
                layoutSelected.value = item.id
              })
            })  
            // 回显当前选中容器
            let container = document.querySelector(`#vueIFApp #${layoutSelected.value}`)
            hignLigntContainer(container)                    
          }, 200);          
          document.querySelector('#vueIFApp').addEventListener('click',()=>{
            
            toolBtnsRef.value.hide()
          })
        }
      };
      return App
    }
    try {  
      // 创建Vue应用实例
      const app = createApp(getApp());
      initApp(app)
      // 将应用挂载到DOM上
      app.mount(vueIFApp);    
    } catch (error) {
      console.log('error',error);
    }
  }
}
function handleExport (type) {
  if (type === 'Html') {
    copyToClipboard(htmlStrRef.value)
  }
  if (type === 'Js') {
    copyToClipboard(scriptStrRef.value)
  }
}
// 下载当前布局
function handleDownload () {
  let {htmlStr,scriptStr}  = getPage(layoutArr,pageId.value,{downloadFile:true})
  generateFiles(htmlStr,scriptStr)
}
// 新增当前布局
function addCurrentLayout () {
  layoutManageSaveRef.value.handleAdd()
}

// 打开当前布局
function layoutManageHandle () {
  layoutManageModel.value = JSON.parse(JSON.stringify(toRaw(layoutArr)))
  layoutManageRef.value.dialogVisible = true
}
function layoutManageSaveHandle () {
  layoutManageSaveRef.value.drawer = true
}
// 回显历史数据的布局编辑
function layoutManageSaveEdit (data) {
  pageId.value = data.pageId
  layoutArr.length = 0
  layoutArr.push(...JSON.parse(data.layoutStr))
  handlePreview()
}
// 排序后的保存处理
function layoutManageHandleSave () {
  layoutArr.length = 0
  layoutArr.push(...JSON.parse(JSON.stringify(layoutManageModel.value)))
  handlePreview()
}
// 布局管理点击了编辑
function layoutManageHandleEdit (data) {
  let {boxId} = data
  let editItem = componentsMap.value[boxId]
  editFormItem(editItem)
}
watch(layoutSelected,(newVal)=>{
  console.log('layoutSelected',newVal);
  // itspIframe.value.contentWindow.postMessage({type:'containerSelect',containerId:newVal}, '*');
  let container = document.querySelector(`#vueIFApp #${newVal}`)
  hignLigntContainer(container)
})
function hignLigntContainer (ele) {
    [...document.querySelectorAll('#vueIFApp .container-active')].forEach(ele => {
      ele.classList.remove('container-active')
    })
    ele.classList.add('container-active')  
}
function htmlStrGet() {
  return  `
         <el-form
          label-position="top"
          ref="formRef"
          require-asterisk-position="right"
          :model="form.props"
          :rules="formRules"
        >
          <!-- :trigger="['customChange']" -->
          <el-row :gutter="20">
            <el-col v-bind="currentLayoutOptions">
              <el-form-item prop="product" label="选择产品：">
                <el-input
                  v-model="form.props.product"
                  placeholder="请输入想要购买的产品"
                />
              </el-form-item>
            </el-col> 
          </el-row> 
        </el-form>  
    `
}
function scriptStrGet() {
return `
const formRef = ref()

const form = reactive({
  props: {}
});

const formRules = reactive({
  product: [
    {
      required: true,
      message: '输入想购买的产品',
      trigger: 'change'
    }
  ],
  });   
    totalData = {
      formRef,
      form,
      formRules,
    }
    `
}
</script>
<style lang="scss">
/* 对于Webkit浏览器（如Chrome、Safari） */
::-webkit-scrollbar {
    width: 6px; /* 纵向滚动条的宽度 */
    height: 4px; /* 横向滚动条的高度 */
}

::-webkit-scrollbar-track {
    background: #f1f1f1; /* 滚动条轨道的颜色 */
}

::-webkit-scrollbar-thumb {
    background: #888; /* 滚动条滑块的颜色 */
    border-radius: 6px; /* 滚动条滑块的圆角程度 */
}

::-webkit-scrollbar-thumb:hover {
    background: #555; /* 滚动条滑块在鼠标悬停时的颜色 */
}

/* 对于Firefox浏览器 */
html {
    scrollbar-width: thin; /* 滚动条的宽度 */
    scrollbar-color: #888 #f1f1f1; /* 滚动条滑块的颜色和轨道的颜色 */
}
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
  >span>a{
    cursor: pointer;
    &:hover{
      color: #0000FF;
    }
  }
}
  
</style>
<style lang="scss" scoped>
// 左右布局
.if-home {
  height: 100%;
  display: flex;
  .if-home-left {
    padding: 10px;
    flex-basis: 240px;
    background-color: #FFF;
    height:100%;
    display: flex;
    flex-direction: column;
    .if-home-left-header {
      display: flex;
      >span {
        flex-basis: 140px;
      }
      margin-bottom: 10px;
    }
    .el-collapse {
      // overflow: auto;
      flex: 1;
      :deep .el-collapse-item__content {
        max-height: 620px;
        overflow: auto;        
      }
    }
    :deep .el-collapse-item__header {
      background-color: rgba(56, 146, 112);
      color: #FFF;
    }
    .component-name-box >button {
      width: 100%;
      justify-content: left !important;
      position: relative;
      border: none;
      
      .jiahao {
        position: absolute;
        right:4px;
        top:4px;
      }
    }    
  }
  .if-home-center {
    flex: 1;
    display: flex;
    flex-direction: column;
    .if-home-center-btn {
      margin: 4px;
    }
    iframe {
      width: 100%;
      flex: 1;
    }
    #vueIFApp {
      flex: 1;
      border:1px solid #CCC;
    }
  }
  .if-home-right {
    padding: 10px;
    flex-basis: 300px;
    background-color: #FFF;
  }
  :deep .el-collapse-item__header {
  height: 30px !important;
  line-height: 30px!important;
}
}

.collapse-title {
  padding-left: 10px;
}

// 容器选中样式
#vueIFApp :deep .container-active {
  border: 1px solid #0000FF;
}
</style>
<style lang="scss">
// 全局css，最终要加到实际允许的vue项目中
.form-button-group-div {
  flex: 1;
  text-align: right;
}
</style>
<style lang="scss">
// 全局css控制
.el-layout-header,.el-layout-footer,.el-layout-sidebar {
  display: none !important;
}
  
</style>
